哈囉大家好,我是韋恩,今天是第六天,讓我們來練習Command API吧!
今天我幫大家會有一個練習小試身手,動手玩玩吧!
讓我們先準備開發環境,請參照以下順序建立專案:
yo code
2.依序輸入專案名稱、id等資訊,參考筆者輸入的資訊建立專案:
如果環境建立有問題,請再次參照昨天的詳細教學建立專案與環境喔!
讓我們先開啟一個extension專案吧!
Command API主要只有四個,當我們在extension.ts
中import * as vscode from 'vscode';
的下面輸入vscode.commands.
,我們會看到vscode的intellisense(程式碼自動補全)幫我們列出commands下面可用的方法:
這四個方法的用途分別是:
Command API | 描述 |
---|---|
getCommands | 取得vscode中註冊的commands,可以給一個boolean值決定是否列出vscode內部使用的command(預設會列出),內部command的id均以下劃線開頭。 |
registerCommand | 跟vscode註冊一個可以被keyborad shortcut、extension程式或其他ui元件呼叫(invoke)的命令。註冊同一個command id兩次會產生錯誤。 |
registerTextEditorCommand | 與registerCommand類似,但只有在vscode有開啟文件的editor(active Editor)時才會觸發。 |
executeCommand | 透過給定的commandId執行對應的內建或extension註冊的command。 |
簡單介紹完,讓們開始動手練習吧,練習才是最實在的。
經過昨天的教學,相信大家都了解怎麼樣設定extension吧,這裡不多贅述。
Contribution Points
配置:讓我們照以下指示設定extension專案,首先於packagage.json,我們要在Contribution Points
裡設定四個Command練習API,如下所示:
{
...
"contributes": {
"commands": [
{
"command": "day06-command-practice.helloWorld",
"title": "Hello World"
},
{
"command": "day06-command-practice.getCommand",
"title": "getCommand"
},
{
"command": "day06-command-practice.textEditorCommand",
"title": "textEditorCommand"
},
{
"command": "day06-command-practice.executeCommand",
"title": "executeCommand"
}
]
},
...
}
activationEvents
配置:設置完Command後,我們一樣要在package.json
配置activationEvents,不過今天的設定有點不一樣,我們不會直接指定onCommand事件,如下所示:
{
...
"activationEvents": [
"*"
],
...
}
ActiveEvents這邊我們設為*
,表示說我們開發用的extenions將在VSCode啟動(Startup)的時候自動活躍並執行active function。為什麼這麼設定呢?就User的角度,會希望安裝的extension在需要使用的時候再執行,避免再不需要使用extension的時候開著extension消耗系統資源。所以會利用指令ActivationEvents來適當的激活我們的extension。但我們在開發時,會相當的不方便,因此在開發或練習階段,我們先直接設定extension自vscode啟動時即會開始活躍。
extension.ts
範例程式配置:我們會在extension.ts
的active funtion這邊註冊四個對應Contribution Points
的commands清單的command,分別執行並展示getCommand、registerTextEditorCommand、registerCommand、executeCommand這四個api,如下所示:
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
const getCmd = vscode.commands.registerCommand('day06-command-practice.getCommand', () => {
vscode.commands.getCommands(false).then((data) => {
console.log('commands', data);
});
});
const txtCmd = vscode.commands.registerTextEditorCommand('day06-command-practice.textEditorCommand', () => {
vscode.window.showInformationMessage('Show Message Only when there is an active editor!');
});
const registerCmd = vscode.commands.registerCommand('day06-command-practice.helloWorld', () => {
vscode.window.showInformationMessage('Hello World from day06-command-practice!');
});
const registerExecCmd = vscode.commands.registerCommand('day06-command-practice.executeCommand', async () => {
await vscode.commands.executeCommand('workbench.action.togglePanel');
vscode.window.showInformationMessage('Panel has been toggle!');
});
context.subscriptions.push(getCmd, txtCmd, registerCmd, registerExecCmd);
}
export function deactivate() {}
請讀者照順序配置今天的vscode專案,接下來,我們要開始啟動extension,並演示對應的結果。
範例專案中註冊的command分別對應到四個api,由於registerCommand昨天已經演示過,因此這裡不多做說明,讀者可以自行嘗試執行這個api,讓我們一一執行其餘三個command,並查看對應結果。
首先,讓我們按F5
執行我們的extension程式。
const getCmd = vscode.commands.registerCommand('day06-command-practice.getCommand', () => {
vscode.commands.getCommands(false).then((data) => {
console.log('commands', data);
});
});
像昨天一樣,我們透過Command Palette搜尋到對應的getCommand命令。
選中後執行它,getCommands方法會回傳一個thenable,thenable
等同js裡的promise,因此我們可以像promise一樣操縱它。在then的callback裡拿到command的資料後,我們會在debug console那邊看到拿到的command array,多達千個,並點擊將其展開。
我們可以看到commands裡面,有著以下劃線(underscore)開頭的command,那即是vscode內部使用的命令。
若我們傳給getCommand一個true的boolean,如
vscode.commands.getCommands(true).then((data) => ... );
內部command即不會被顯示出來。
reisterEditorCommand需要在有editor開啟的狀況下才會觸發,因此我們先關掉editor執行看看。
Ok,什麼都不會發生,這是正常的。
讓我們打開任一個文件並再次執行看看,
開啟編輯器後,我們執行textEditorCommand總算在右下角順利地跳出訊息,
- 使用executeCommand:
const registerExecCmd = vscode.commands.registerCommand('day06-command-practice.executeCommand', async () => {
await vscode.commands.executeCommand('workbench.action.togglePanel');
vscode.window.showInformationMessage('Panel has been toggle!');
});
總算,我們來到今天的重頭戲了,executeCommand,可以讓我們執行任意被註冊的command。
讓我們先來看看上面的範例程式,我們可以看到這裡我們一樣可以使用async跟await處理非同步的executeCommand事件回傳的thenable。executeCommand會執行VSCode內建的togglePanel的命令,用於開關我們的terminal,當我們在vscode裡面使用⌃
+`開關terminal時,其實用的就是這個指令。
動手看看吧,我們一樣使用Command Palette執行指令。
成功後,右下方一樣會跳出訊息,同時panel會被開關。
恭喜,您已經嘗試過手動執行這幾個api了,相信一定更為熟悉。現在,我們有一個練習,讓我們找出內建的command操作Editor的Sidebar元件吧!
這裡推薦的解答方向有兩個:
查找官方文件,最詳細的莫過於keybings.json這一章。
使用keyborad shortcut搜尋command
這裡我會使用第二種方式示範如何找到未知的command,先讓我們進入keyboard shortcut。
然後,還記得嗎,第二天我們提到了workbench
這個namespace,workbench的namespace下面會有種種跟editor元件有關的設定跟command。因此,我們使用這個作為第一個關鍵字做查找。
接下來,讓我們第二天介紹的sidebar,它也是重要的關鍵字,因此我們這麼輸入:
可以看到,keyboard shortcut支援fuzzy search,因此在多個關鍵字下很快就定位到了符合我們需求的command id: workbench.action.toggleSidebarVisibility
。
讓我們直接選取它,並按上右鍵,此時會跳出一個選單。
Wow,原來選單上面有一個copy command id
選項! 真的太好了,恩,你知道的,複製下來吧!
現在,讓我們把新的command id貼在原本要執行的command上
const registerExecCmd = vscode.commands.registerCommand('day06-command-practice.executeCommand', async () => {
await vscode.commands.executeCommand('workbench.action.toggleSidebarVisibility');
vscode.window.showInformationMessage('Panel has been toggle!');
});
我們很快速的滿足了上述需求。
讓我們再次按下F5
執行我們的extension,並檢視結果吧!
註: VSCode提供的編輯器command,像今天練習查找到的workbench下command,為simple command,不需要特別傳入參數並拿到回傳結果,另外有build-in command,為更複雜的command,無法在keyboard shortcut上找尋的到,如要查找這類command就一定需要查找官方文件了。
好啦,今天我們的練習就在這裡告一個段落了,不小心又超過了6000多字,然而,真的要更詳細,其實還有很多detail可以說明啊!
請讀者別擔心! 其實啊,說不完、學不完,很正常的。
這些學不完的東西,是要靠著我們自學
與摸索
而獲得的。天底下,從來沒有不勞而獲的東西,唯有自己練習過的,嘗試過的,才會是自己的。因此,筆者這裡主要在這裏帶大家嘗試練習api並練習找尋答案
與查找文件
,學習的api雖然不多,但唯希望,在這一章節嘗試過、找尋過答案的經驗,能夠能為你未來學習任何程式語言或框架的寶貴資產。